package com.dream21th.gateway.fliter;

import com.dream21th.common.enums.SafeLevelEnum;
import com.dream21th.common.utils.AesEncryptUtil;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;
import java.util.List;

@Slf4j
@Component
public class PostFilter implements GlobalFilter, Ordered {

    private static Joiner joiner = Joiner.on("");//将 List 数据以""分隔进行拼接

    @Value("${key.aes.encode.key}")
    private String aesKey;

    @Value("${key.aes.encode.vi}")
    private String aesVi;

    @Override
    public int getOrder() {
        // -1 is response write filter, must be called before that
        return -2;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders headers = request.getHeaders();
        String safeLevel = headers.getFirst("safe_level");
        if (!StringUtils.equals(SafeLevelEnum.HIGH.code, safeLevel)) {
            return chain.filter(exchange);
        }
        ServerHttpResponse originalResponse = exchange.getResponse();
        HttpHeaders httpHeaders = originalResponse.getHeaders();
        httpHeaders.add("Content-Type", "application/json; charset=UTF-8");
        originalResponse.getHeaders().remove("Content-Length");

        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
      /*  ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.map(dataBuffer -> {

                        try {
                            // probably should reuse buffers
                            byte[] content = new byte[dataBuffer.readableByteCount()];
                            dataBuffer.read(content);
                            //释放掉内存
                            DataBufferUtils.release(dataBuffer);
                            String s = new String(content, Charset.forName("UTF-8"));
                            String encrypt = AesEncryptUtil.encrypt(s, aesKey, aesVi);
                            String md5 = DigestUtils.md5DigestAsHex(encrypt.getBytes());

                            byte[] uppedContent = new String(encrypt.getBytes(), Charset.forName("UTF-8")).getBytes();
                            originalResponse.getHeaders().add("encrypt",md5);
                            return bufferFactory.wrap(uppedContent);
                        } catch (Exception e) {
                            return null;
                        }
                    }));
                }
                // if body is not a flux. never got there.
                return super.writeWith(body);
            }
        };*/

        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {

            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                log.info("body:{},getStatusCode():{}", body, getStatusCode());
                if (getStatusCode() != null && getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                    return super.writeWith(fluxBody.buffer().map(dataBuffers -> {//解决返回体分段传输
                        List<String> list = Lists.newArrayList();
                        dataBuffers.forEach(dataBuffer -> {
                            byte[] content = new byte[dataBuffer.readableByteCount()];
                            dataBuffer.read(content);
                            DataBufferUtils.release(dataBuffer);
                            try {
                                list.add(new String(content, "utf-8"));
                            } catch (Exception e) {
                                log.error("--list.add--error", e);
                            }
                        });
                        String responseData = joiner.join(list);
                       // String resStr = CommonMethod.resSetResult(responseData);
                        String encrypt = null;
                        try {
                            encrypt = AesEncryptUtil.encrypt(responseData, aesKey, aesVi);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        String md5 = DigestUtils.md5DigestAsHex(encrypt.getBytes());

                        byte[] uppedContent = new String(encrypt.getBytes(), Charset.forName("UTF-8")).getBytes();
                        originalResponse.getHeaders().add("encrypt",md5);
                        originalResponse.getHeaders().setContentLength(uppedContent.length);
                        return bufferFactory.wrap(uppedContent);
                    }));
                }
                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }
}
